package com.glsc.ngateway.platform.service.it.networkAssets;

import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.networkassets.MaintenanceInformation;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.networkassets.NetworkAssetMaintenance;
import com.glsc.ngateway.common.api.platform.dto.it.networkassets.DashboardDto;
import com.glsc.ngateway.common.api.common.dto.PageQueryParamDto;
import com.glsc.ngateway.common.api.platform.dto.it.networkassets.MaintenanceInformationDto;
import com.glsc.ngateway.common.api.platform.dto.it.networkassets.NetworkAssetMaintenanceDto;
import com.glsc.ngateway.common.base.converter.platform.MaintenanceInformationConverter;
import com.glsc.ngateway.common.base.converter.platform.NetworkAssetMaintenanceConverter;
import com.glsc.ngateway.common.base.exception.PlatformException;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.it.networkAssets.MaintenanceInformationRepo;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.it.networkAssets.NetworkAssetMaintenanceRepo;
import com.glsc.ngateway.platform.utils.report.ReportFileConfigEnum;
import com.glsc.ngateway.platform.utils.report.ReportFileUtil;
import com.glsc.ngateway.platform.utils.report.ReportUploadContext;
import io.jsonwebtoken.lang.Collections;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.time.LocalDate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 网络资产-网络资产维护
 */
@Service
public class NetworkAssetMaintenanceService {
    private static final Logger LOGGER = LoggerFactory.getLogger(NetworkAssetMaintenanceService.class);

    @Autowired
    private NetworkAssetMaintenanceRepo networkAssetMtRepo;

    @Autowired
    private MaintenanceInformationRepo mtInfoRepo;

    /**
     * 查看
     */
    public Page<NetworkAssetMaintenanceDto> query(PageQueryParamDto<NetworkAssetMaintenanceDto> param) throws Exception {
        param.setParam(Objects.isNull(param.getParam()) ? new NetworkAssetMaintenanceDto() : param.getParam());
        Pageable pageable = param.getPageable();
        Page<NetworkAssetMaintenance> pageRes = networkAssetMtRepo.page(pageable, param.getParam());
        List<NetworkAssetMaintenanceDto> domain = NetworkAssetMaintenanceConverter.do2Dto(pageRes.getContent());
        domain.forEach(c -> c.setMaintenanceInfoList(MaintenanceInformationConverter.do2Dto(mtInfoRepo.findAllBySerialNum(c.getSerialNum()))));
        return new PageImpl<>(domain, pageable, pageRes.getTotalElements());
    }

    public byte[] export(NetworkAssetMaintenanceDto param) throws IOException {
        List<NetworkAssetMaintenanceDto> datas = NetworkAssetMaintenanceConverter.do2Dto(networkAssetMtRepo.queryAll(param));
        return ReportFileUtil.export(datas, ReportFileConfigEnum.NETWORK_ASSET_MAINTENANCE);
    }

    /**
     * 上传文件批量编辑
     */
    public ReportUploadContext<NetworkAssetMaintenanceDto, String> upload(MultipartFile file) throws IOException {
        ReportUploadContext<NetworkAssetMaintenanceDto, String> context = ReportUploadContext.<NetworkAssetMaintenanceDto, String>builder()
                .config(ReportFileConfigEnum.NETWORK_ASSET_MAINTENANCE)
                .file(file)
                .check(this::check)
                .build();
        ReportFileUtil.readSingleExcel(context);
        //全部检查通过后添加或修改数据
        if (context.isCheckPass()) {
            networkAssetMtRepo.saveAll(NetworkAssetMaintenanceConverter.dto2Do(context.getReadRes()));
            //批量导入时，关联维保信息暂不处理
        }
        return context;
    }

    /**
     * 删除
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(@NotNull Long id) {
        networkAssetMtRepo.deleteById(id);
    }

    /**
     * 添加/修改
     */
    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdate(@NotNull NetworkAssetMaintenanceDto networkAssetMtDto) {
        check(networkAssetMtDto);
        NetworkAssetMaintenance save = networkAssetMtRepo.save(NetworkAssetMaintenanceConverter.dto2Do(networkAssetMtDto));
        String serialNum = save.getSerialNum();
        //新的维保信息
        List<MaintenanceInformationDto> newList = Collections.isEmpty(networkAssetMtDto.getMaintenanceInfoList()) ?
                java.util.Collections.EMPTY_LIST : networkAssetMtDto.getMaintenanceInfoList();
        Set<Long> newMtInfoIds = newList.stream().map(MaintenanceInformationDto::getId).collect(Collectors.toSet());
        //旧的维保信息
        List<MaintenanceInformation> oldList = mtInfoRepo.findAllBySerialNum(serialNum);
        //找出需要取消关联的维保信息Ids
        Set<Long> unConnectIds = Collections.isEmpty(oldList) ? java.util.Collections.EMPTY_SET
                : oldList.stream().map(MaintenanceInformation::getId).filter(id -> !newMtInfoIds.contains(id)).collect(Collectors.toSet());
        //关联维保信息
        if (!Collections.isEmpty(newMtInfoIds)) {
            mtInfoRepo.connectMains(newMtInfoIds, serialNum);
        }
        if (!Collections.isEmpty(unConnectIds)) {
            mtInfoRepo.unconnectMains(newMtInfoIds);
        }
    }

    public void check(NetworkAssetMaintenanceDto networkAssetMtDto) {
        if (StringUtils.isBlank(networkAssetMtDto.getSerialNum())) {
            throw PlatformException.error("[序列号]项必填", false, false);
        }
        if (networkAssetMtRepo.existsBySerialNum(networkAssetMtDto.getId(), networkAssetMtDto.getSerialNum()) > 0) {
            throw PlatformException.error("[序列号]项重复", false, false);
        }
        if (StringUtils.isBlank(networkAssetMtDto.getStatus())) {
            throw PlatformException.error("[状态]项必填", false, false);
        }
    }

    /**
     * 获取dashboard数据
     * 第一张柱状图以【网络资产维护】表中vendor字段进行count数量统计，
     * 第二张柱状图，以【网络资产维护】表中status字段进行count数量统计，
     * 第三张柱状图以【网络资产维护】表中manufactureDate字段进行计算，与当前日期相差的年数<=3、>3且<=5、>5且<=6、>6四个维度来进行count数量统计
     */
    public DashboardDto getDashboard() {
        LocalDate nowDate = LocalDate.now();
        DashboardDto.DashboardDetailVo vendorGroup = new DashboardDto.DashboardDetailVo(
                networkAssetMtRepo.gourpByVendor()
                        .stream()
                        //count这里必须这样转
                        .collect(Collectors.toMap(m -> String.valueOf(m.get("vendor")), m -> Integer.valueOf(String.valueOf(m.get("count")))))
        );
        DashboardDto.DashboardDetailVo statusGroup = new DashboardDto.DashboardDetailVo(
                networkAssetMtRepo.gourpByStatus()
                        .stream()
                        //count这里必须这样转
                        .collect(Collectors.toMap(m -> String.valueOf(m.get("status")), m -> Integer.valueOf(String.valueOf(m.get("count")))))
        );
        DashboardDto.DashboardDetailVo manufactureateDateGroup = new DashboardDto.DashboardDetailVo(
                new LinkedHashMap<>() {{
                    put("不超过3年", networkAssetMtRepo.gourpByManufactureateDate(nowDate.minusYears(3), null));
                    put("3-5年", networkAssetMtRepo.gourpByManufactureateDate(nowDate.minusYears(5), nowDate.minusYears(3)));
                    put("5-6年", networkAssetMtRepo.gourpByManufactureateDate(nowDate.minusYears(6), nowDate.minusYears(5)));
                    put("超过6年", networkAssetMtRepo.gourpByManufactureateDate(null, nowDate.minusYears(6)));
                }});
        return DashboardDto.builder()
                .vendorGroup(vendorGroup)
                .statusGroup(statusGroup)
                .manufactureateDateGroup(manufactureateDateGroup)
                .build();
    }

    public List<NetworkAssetMaintenance> findAllByBindSerialNumList(List<String> serialNumList) {
        return CollectionUtils.isEmpty(serialNumList) ? java.util.Collections.EMPTY_LIST : networkAssetMtRepo.findAllBySerialNumIn(serialNumList);
    }
}
